package lambdasinaction.chap2;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

/**
 * chapter2
 * 行为参数化，用谓词筛选苹果
 * 灵活：行为参数化（类、匿名类、Lambda）
 * 死板：值参数化
 * @author Fish
 * @since 0.0.1 2018/7/15 17:10
 */
public class MyFilterApples {

  public static void main(String[] args) {
    List<Apple> inventory = Arrays.asList(new Apple("red", 151),
        new Apple("green", 120),
        new Apple("green", 80));

    // 传统使用方法
//    List<Apple> greenApples = filterApplesByColor(inventory, "green");
//    System.out.println(greenApples);
//
    // 策略设计模式，选择不同的苹果策略
    // 行为参数化：让方法接受多种行为（或战略）作为参数，并在内部使用，来完成不同的行为。
    // 谓词：即返回一个 boolean 值的函数
    // 对选择标准建模
//    List<Apple> redApples = filterApplesByColor(inventory, "red");
//    System.out.println(redApples);

//    List<Apple> greenApples = filter(inventory, new AppleColorPredicate());
//    System.out.println(greenApples);
//
//    List<Apple> heavyApples = filter(inventory, new AppleWeightPredicate());
//    System.out.println(heavyApples);

//    List<Apple> redAndHeavyApples = filter(inventory, new AppleRedAndHeavyPredicate());
//    System.out.println(redAndHeavyApples);

    // 匿名类和你熟悉的 Java 局部类（块中定义的类）差不多，但匿名类没有名字。它允许你同时声明并实例化一个类。换句话说，它允许你随用随建。
//    List<Apple> redApples2 = filter(inventory, new ApplePredicate() { // 直接内联参数化方法的行为
//      @Override
//      public boolean test(Apple apple) {
//        return apple.getColor().equals("red");
//      }
//    });
//    System.out.println(redApples2);

    // 使用 Lambda 表达式
    List<Apple> redApples = filter(inventory, (Apple a) -> a.getColor().equals("color"));
    System.out.println(redApples);
  }

  interface ApplePredicate {

    boolean test(Apple apple);
  }


  /**
   * 选择较重苹果的谓词
   */
  static class AppleWeightPredicate implements ApplePredicate {

    @Override
    public boolean test(Apple apple) {
      return apple.getWeight() > 150;
    }
  }

  /**
   * 选择绿苹果的谓词
   */
  static class AppleColorPredicate implements ApplePredicate {

    @Override
    public boolean test(Apple apple) {
      return apple.getColor().equals("green");
    }
  }

  static class AppleRedAndHeavyPredicate implements ApplePredicate {

    @Override
    public boolean test(Apple apple) {
      return apple.getColor().equals("red") && apple.getWeight() > 150;
    }
  }

  public static List<Apple> filterApplesByColor(List<Apple> inventory, String color) {
    List<Apple> result = new ArrayList<>();
    for (Apple apple : inventory) {
      if (apple.getColor().equals(color)) {
        result.add(apple);
      }
    }
    return result;
  }

  /**
   * 根据抽象条件筛选，谓词对象封装了测试苹果的条件
   * @param inventory
   * @param predicate
   * @return
   */
  public static List<Apple> filter(List<Apple> inventory, ApplePredicate predicate) {
    List<Apple> result = new ArrayList<>();
    for (Apple apple : inventory) {
      if (predicate.test(apple)) {
        result.add(apple);
      }
    }
    return result;
  }


  public static class Apple {

    private String color;
    private Integer weight;

    public Apple(String color, Integer weight) {
      this.color = color;
      this.weight = weight;
    }

    public String getColor() {
      return color;
    }

    public void setColor(String color) {
      this.color = color;
    }

    public Integer getWeight() {
      return weight;
    }

    public void setWeight(Integer weight) {
      this.weight = weight;
    }

    @Override
    public String toString() {
      return "Apple{" +
          "color='" + color + '\'' +
          ", weight=" + weight +
          '}';
    }
  }

}
